package com.suray.wcs.service.core.util;

import com.suray.wcs.service.pojo.Device;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.Socket;
import java.util.LinkedList;

/**
 * 称重.
 *
 * @author chenrui
 */
public class WeightterUtil {
    private volatile boolean runFlag = false;

    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 称重类型字符串.
     */
    public static String WEIGHTTER_TYPE_DEFULT = "DEFULT";
    public static String WEIGHTTER_TYPE_OTHER = "OTHER";

    /**
     * 称重类型.
     */
    private String weightterType = WEIGHTTER_TYPE_OTHER;

    /**
     * 抖动范围.
     */
    final private static double OFFSET = 0.2;

    /**
     * 最小重量.
     */
    final private static double MIN_WEIGHT = 1;
    /**
     * 称重重校验.
     */
    final private static double WEIGHT = 0;
    /**
     * 称重重校验.
     */
    final private static double HIGWEIGHT = 1000;
    /**
     * 扫描间隔.
     */
    final private static int SLEEP_SCHEDULE = 200;

    /**
     * 稳定扫描时间.
     */
    final private static int STABLE_SCHEDULE = 2000;

    /**
     * 空值超时时间.
     */
    final private static int TIMEOUT = 5000;

    /**
     * 称重.
     */
    private Device weightInfo;

    /**
     * 净重.
     */
    private double netWeight;

    private LinkedList<Double> netWeightList = new LinkedList<Double>();

    public WeightterUtil(String ip, String port) {
        Device weightInfo = new Device();
        weightInfo.setIp(ip);
        weightInfo.setPort(Integer.parseInt(port));
        this.weightInfo = weightInfo;
    }

    /**
     * 开始称重.
     *
     * @return
     */
    public synchronized double getWeight() {
        Socket socket = null;
        InputStream in = null;
        OutputStream out = null;
        try {
            socket = new Socket(weightInfo.getIp(), weightInfo.getPort());
            socket.setSoTimeout(TIMEOUT);
            in = socket.getInputStream();
            out = socket.getOutputStream();
            int noResultCount = 0;
            while (true) {
                // 将inputStream全部读取清空.
                in.read();
                double weight = getWeightValue(in);
                log.info("实时重量：" + weight);
                // 空值报警.
                if (weight == 0) {
                    if (noResultCount > TIMEOUT / SLEEP_SCHEDULE) {
                        // TODO 报警.
                        log.error("读取超时！");
                        break;
                    }
                    noResultCount++;
                    Thread.sleep(SLEEP_SCHEDULE);
                    continue;
                }
                // 称重缓存列表.
                if (netWeightList.size() == 0) {
                    netWeightList.add(weight);
                } else if (Math.abs(weight - netWeightList.get(0)) > OFFSET) {
                    netWeightList.removeFirst();
                    netWeightList.add(weight);
                } else {
                    netWeightList.add(weight);
                }
                // 计算稳定平均值.
                if (netWeightList.size() >= STABLE_SCHEDULE / SLEEP_SCHEDULE) {
                    double weight4Sum = 0;
                    for (double weight4SumUnit : netWeightList) {
                        System.err.println("weight4SumUnit" + weight4SumUnit);
                        weight4Sum += weight4SumUnit;
                    }
                    double weight4Avg = weight4Sum / netWeightList.size();
                    BigDecimal bigDecimal = new BigDecimal(weight4Avg);
                    this.netWeight = bigDecimal.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
                    netWeightList.clear();
                    log.info(weightInfo.getIp() + ":" + weightInfo.getPort() + " 获取重量【" + netWeight + "】.");
                    if (netWeight > WEIGHT && netWeight < HIGWEIGHT) {// 大于2kg，小于等于50kg
                        System.out.println(weightInfo.getIp() + ":" + weightInfo.getPort() + " 发送称重完成。。。。。。。。。。。。。。");
                    } else {
                        netWeight = -1;
//						Plc.deviceBaseNameMap.get(weightInfo.getName()).getPlc()
                        System.out.println(weightInfo.getIp() + ":" + weightInfo.getPort() + " 发送称重错误。。。。。。。。。。。。。。");
                    }
                    break;
                }
                // 扫描休眠.
                Thread.sleep(SLEEP_SCHEDULE);
            }

        } catch (Exception e) {
            log.error(weightInfo.getIp() + ":" + weightInfo.getPort() + "扫码通讯失败:" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return netWeight;
    }

    /**
     * 获取单个有效值[净重].
     *
     * @return
     * @throws IOException
     */
    private double getWeightValue(InputStream in) throws IOException {
        byte[] b = new byte[24];
        int count = 0;
        double tempNetWeight = 0;
        while (count < 500) {
            count++;
            int i = in.read(b);
            if (i > 0) {
                String str = new String(b);
                if (str == null || "".equals(str)) {
                    break;
                }
                int endIndex = 15;
                if (WEIGHTTER_TYPE_DEFULT.equals(weightterType)) {
                    endIndex = 15;
                } else if (WEIGHTTER_TYPE_OTHER.equals(weightterType)) {
                    endIndex = 13;
                }
                String netWeightStr = str.substring(4, endIndex);
                if (netWeightStr == null || "".equals(netWeightStr)) {
                    continue;
                }
                try {
                    tempNetWeight = Double.valueOf(netWeightStr.trim());
                    if (WEIGHTTER_TYPE_OTHER.equals(weightterType)) {
                        tempNetWeight = tempNetWeight / 10;
                    }
                } catch (Exception e) {
                    continue;
                }
                if (tempNetWeight > MIN_WEIGHT) {
                    return tempNetWeight;
                }
                return 0;
            }
        }
        return 0;
    }

    public double getNetWeight() {
        return netWeight;
    }

    public boolean isRunFlag() {
        return runFlag;
    }

    public void setRunFlag(boolean runFlag) {
        this.runFlag = runFlag;
    }

    public String getWeightterType() {
        return weightterType;
    }

}
